package ooo.reindeer.data.annotation;

import ooo.reindeer.data.option.Type;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;

public class  AnnotationUtil {
    static final Map<String, Type> typeMap = new ConcurrentHashMap<String, Type>();
    static final Map<Class, Type> calssTypeMap = new ConcurrentHashMap<Class, Type>();
    static final Map<Class, Method> typeMethodMap = new ConcurrentHashMap<Class, Method>();
    static final Set<Class> exceptionSet = new CopyOnWriteArraySet<Class>();

    static {
        for (Type value : Type.values()) {
            typeMap.put(value.name(), value);
        }
    }

    static public Annotation getAnnotation(Annotation[] annotations) {
        for (Annotation annotation : annotations) {
            Class clazz = annotation.getClass();

            if (exceptionSet.contains(clazz)) continue;

            Type type = calssTypeMap.get(clazz);
            if (type == null) {
                Class clazz2 = annotation.annotationType();
                type = typeMap.get(clazz2.getSimpleName());
                if (type != null) {
                    calssTypeMap.put(clazz, type);

                    try {
                        typeMethodMap.put(clazz, clazz.getDeclaredMethod("type"));
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }

                    return annotation;
                } else {
                    exceptionSet.add(clazz);
                }
            } else {
                return annotation;
            }
        }
        return null;
    }

    static public Method getTypeMethod(Annotation annotation) {
        Method method=null;
        while((method=typeMethodMap.get(annotation.getClass())) == null){
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
            }
        };
        return method;
    }
}
